using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
using FastDevTemplate.Api.Model.Base;
using FastDevTemplate.Common.Util;
using Microsoft.AspNetCore.Mvc;

namespace FastDevTemplate.Api.Base;

[ApiController]
public class BaseController : ControllerBase
{
    public (bool isValid, string[] messages) ValidateModel<T>(T? model)
        where T : notnull
    {
        if (model == null)
            return (false, ["参数错误"]);
        var context = new ValidationContext(model, null, null);
        var results = new List<ValidationResult>();
        var isValid = Validator.TryValidateObject(model, context, results, true);
        return (isValid, messages: results.Select(item=>item.ToString()).ToArray());
    }

    protected Guid? GetUUID()
    {
        var uuid = HttpContext.Request.Headers["uuid"].FirstOrDefault();
        if (uuid != null)
            return Guid.Parse(uuid);
        return null;
    }

    protected string? GetToken()
    {
        return HttpContext.Request.Headers["token"].FirstOrDefault();
    }

    protected HttpResult<TReturn> CheckResult<TReturn>(TReturn? resultModel)
    {
        if (resultModel == null)
            return BadResult<TReturn>();
        return OkResult(resultModel);
    }

    protected static HttpResult OkResult()
    {
        return new HttpResult
        {
            Code = 1,
            Msg = "请求成功"
        };
    }

    protected static HttpResult<T> OkResult<T>(T obj, int code = 1)
    {
        return new HttpResult<T>
        {
            Code = code,
            Data = obj,
            Msg = "请求成功"
        };
    }

    protected static HttpResult BadResult(int code = -1, string msg = "请求失败")
    {
        if (code > 0)
            throw new ApplicationException("code can't be NoError");
        return new HttpResult
        {
            Code = code,
            Msg = msg
        };
    }

    protected static HttpResult<T> BadResult<T>(int code = -1, string msg = "请求失败")
    {
        if (code > 0)
            throw new ApplicationException("code can't be NoError");
        return new HttpResult<T>
        {
            Code = code,
            Msg = msg
        };
    }

    protected static HttpResult CodeResult(int code)
    {
        if (code > 0)
            return OkResult();
        else
        {
            return new HttpResult
            {
                Code = code,
                Msg = ExceptionFactory.GetErrorMessage(code)
            };
        }
    }
    protected static HttpResult<T> CodeResult<T>(T obj, int code)
    {
        if (code > 0)
            return OkResult(obj, code);
        else
        {
            return new HttpResult<T>
            {
                Code = code,
                Msg = ExceptionFactory.GetErrorMessage(code)
            };
        }
    }

    public enum ExpressionType
    {
        Contains,
        Equal,
        Less,
        Greater,
        LessEqual,
        GreaterEqual,
        
    }

    protected static Expression<Func<T, bool>> GenerationExpression<T>(string key, string value, ExpressionType expressionType)
    {
        var parameter = Expression.Parameter(typeof(T), "x");
        var property = Expression.Property(parameter, key);
        var constant = Expression.Constant(value);
        
        Expression body;
        switch (expressionType)
        {
            case ExpressionType.Contains:
                body = Expression.Call(property, typeof(string).GetMethod("Contains", new[] { typeof(string) })!, constant);
                break;
            case ExpressionType.Equal:
                body = Expression.Equal(property, constant);
                break;
            case ExpressionType.Less:
                body = Expression.LessThan(property, constant);
                break;
            case ExpressionType.Greater:
                body = Expression.GreaterThan(property, constant);
                break;
            case ExpressionType.LessEqual:
                body = Expression.LessThanOrEqual(property, constant);
                break;
            case ExpressionType.GreaterEqual:
                body = Expression.GreaterThanOrEqual(property, constant);
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(expressionType), expressionType, null);
        }
        
        return Expression.Lambda<Func<T, bool>>(body, parameter);
    }
    
    protected static List<Expression<Func<T, bool>>> DeserializeQueryParameters<T>(
        object? queryParameters, 
        ExpressionType expressionType = ExpressionType.Contains,
        string[]? ignoreKeys = null
        )
        where T : class
    {
        var expressions = new List<Expression<Func<T, bool>>>();
        if (queryParameters == null)
            return expressions;
        foreach (var property in queryParameters.GetType().GetProperties())
        {
            if (ignoreKeys != null && ignoreKeys.Contains(property.Name))
                continue;
            var value = property.GetValue(queryParameters)?.ToString();
            if (!string.IsNullOrEmpty(value))
            {
                var expression = GenerationExpression<T>(property.Name, value, expressionType);
                expressions.Add(expression);
            }
        }
        return expressions;
    }
    
}